package com.mysqlpass.update.controller;

import com.mysqlpass.update.model.ApiResponse;
import com.mysqlpass.update.model.UpdateInfo;
import com.mysqlpass.update.service.UpdateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 更新服务控制器，提供检查更新和下载更新文件的API
 */
@RestController
@RequestMapping("/update")
public class UpdateController {
    
    private static final Logger logger = LoggerFactory.getLogger(UpdateController.class);
    
    @Autowired
    private UpdateService updateService;
    
    @Value("${update.file.directory}")
    private String updateFileDirectory;
    
    @Value("${update.file.file-name}")
    private String updateFileName;
    
    /**
     * 检查是否有新的更新可用
     * @param clientVersion 加密后的客户端当前版本号
     * @return 封装更新信息的ApiResponse对象
     */
   
    @RequestMapping(value = "/check", method = {RequestMethod.GET, RequestMethod.POST})
    public ResponseEntity<ApiResponse<UpdateInfo>> checkUpdate(@RequestParam String clientVersion, HttpServletRequest request) {
        String clientIp = getClientIp(request);
        logger.info(String.format("[IP: %s] 收到更新检查请求，加密的客户端版本: %s", clientIp, clientVersion));
        
        try {
            // 解密客户端版本号
            String decryptedVersion = decryptVersion(clientVersion);
            logger.info(String.format("[IP: %s] 版本解密成功，原始版本: %s", clientIp, decryptedVersion));
            
            // 调用服务层进行更新检查
            UpdateInfo updateInfo = updateService.checkUpdate(decryptedVersion);
            
            // 记录更新检查结果
            logger.info(String.format("[IP: %s] 更新检查完成，当前版本: %s, 最新版本: %s, 需要更新: %s", 
                    clientIp, updateInfo.getCurrentVersion(), updateInfo.getLatestVersion(), updateInfo.isNeedUpdate()));
            
            // 使用ApiResponse封装响应数据
            ApiResponse<UpdateInfo> response = ApiResponse.success("更新检查成功", updateInfo);
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            logger.error("[IP: {}] 更新检查失败: {}", clientIp, e.getMessage(), e);
            ApiResponse<UpdateInfo> errorResponse = ApiResponse.fail(500, "更新检查失败: " + e.getMessage());
            return ResponseEntity.ok(errorResponse);
        }
    }
    
    /**
     * 测试中文日志显示的端点
     */
    @GetMapping("/test-chinese-log")
    public ResponseEntity<ApiResponse<String>> testChineseLog() {
        // 记录中文字符串到日志
        logger.info("这是一条测试中文日志，用于验证中文显示是否正常。");
        logger.info("日志记录 - 中文测试：你好，世界！");
        logger.info("特殊字符测试：中文、English、日本語、한국어");
        
        // 使用ApiResponse封装响应数据
        ApiResponse<String> response = ApiResponse.success("测试中文日志已记录，请查看服务器日志", "中文测试成功");
        return ResponseEntity.ok(response);
    }
    
    /**
     * 测试更新检查功能的端点（无需加密）
     */
    @RequestMapping(value = "/test-check", method = {RequestMethod.GET, RequestMethod.POST})
    public ResponseEntity<ApiResponse<UpdateInfo>> testCheckUpdate(@RequestParam String clientVersion, HttpServletRequest request) {
        String clientIp = getClientIp(request);
        logger.info(String.format("[IP: %s] 收到测试更新检查请求，客户端版本: %s", clientIp, clientVersion));
        
        try {
            // 直接使用传入的版本号，不进行解密
            UpdateInfo updateInfo = updateService.checkUpdate(clientVersion);
            
            // 记录更新检查结果
            logger.info(String.format("[IP: %s] 更新检查完成，当前版本: %s, 最新版本: %s, 需要更新: %s", 
                    clientIp, updateInfo.getCurrentVersion(), updateInfo.getLatestVersion(), updateInfo.isNeedUpdate()));
            
            // 使用ApiResponse封装响应数据
            ApiResponse<UpdateInfo> response = ApiResponse.success("测试更新检查成功", updateInfo);
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            logger.error(String.format("[IP: %s] 更新检查失败: %s", clientIp, e.getMessage()), e);
            ApiResponse<UpdateInfo> errorResponse = ApiResponse.fail(500, "测试更新检查失败: " + e.getMessage());
            return ResponseEntity.status(500).body(errorResponse);
        }
    }
    
     @GetMapping("/mapcheck")
    public ResponseEntity<ApiResponse<UpdateInfo>> checkMapUpdate(@RequestParam Map<String, String> param, HttpServletRequest request) {
        String clientVersion=param.get("clientVersion");
        String clientIp = getClientIp(request);
        if(clientVersion==null){
            logger.warn(String.format("[IP: %s] 收到更新检查请求，但缺少客户端版本参数", clientIp));
            ApiResponse<UpdateInfo> errorResponse = ApiResponse.fail(400, "缺少客户端版本参数");
            return ResponseEntity.badRequest().body(errorResponse);
        }
        logger.info(String.format("[IP: %s] 收到更新检查请求，加密的客户端版本: %s", clientIp, clientVersion));
        
        try {
            // 解密客户端版本号
            String decryptedVersion = decryptVersion(clientVersion);
            logger.info(String.format("[IP: %s] 版本解密成功，原始版本: %s", clientIp, decryptedVersion));
            
            // 调用服务层进行更新检查
            UpdateInfo updateInfo = updateService.checkUpdate(decryptedVersion);
            
            // 记录更新检查结果
            logger.info(String.format("[IP: %s] 更新检查完成，当前版本: %s, 最新版本: %s, 需要更新: %s", 
                    clientIp, updateInfo.getCurrentVersion(), updateInfo.getLatestVersion(), updateInfo.isNeedUpdate()));
            
            // 使用ApiResponse封装响应数据
            ApiResponse<UpdateInfo> response = ApiResponse.success("Map参数更新检查成功", updateInfo);
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            logger.error(String.format("[IP: %s] 更新检查失败: %s", clientIp, e.getMessage()), e);
            ApiResponse<UpdateInfo> errorResponse = ApiResponse.fail(500, "更新检查失败: " + e.getMessage());
            return ResponseEntity.status(500).body(errorResponse);
        }
    }
    /**
     * 下载更新文件
     * @return 文件下载响应
     * 注意：文件下载接口保持原样，不使用ApiResponse封装，因为它返回的是文件流
     */
    @GetMapping("/download")
    public ResponseEntity<Resource> downloadUpdate(HttpServletRequest request) {
        String clientIp = getClientIp(request);
        logger.info(String.format("[IP: %s] 收到更新文件下载请求，文件名: %s", clientIp, updateFileName));
        
        try {
            // 构建更新文件路径
            Path filePath = Paths.get(updateFileDirectory).resolve(updateFileName).normalize();
            logger.debug(String.format("[IP: %s] 构建文件路径: %s", clientIp, filePath.toString()));
            
            // 检查目录是否存在
            if (!Files.exists(Paths.get(updateFileDirectory))) {
                logger.warn(String.format("[IP: %s] 更新文件目录不存在: %s", clientIp, updateFileDirectory));
                return ResponseEntity.notFound().build();
            }
            
            Resource resource = new UrlResource(filePath.toUri());
            
            // 检查文件是否存在和可读
            if (resource.exists() && resource.isReadable()) {
                long fileSize = Files.size(filePath);
                logger.info(String.format("[IP: %s] 开始下载更新文件: %s (大小: %.2f MB)", 
                        clientIp, updateFileName, fileSize / (1024.0 * 1024.0)));
                
                return ResponseEntity.ok()
                        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                        .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileSize))
                        .body(resource);
            } else {
                logger.error(String.format("[IP: %s] 无法读取更新文件: %s, 存在: %s, 可读: %s",
                        clientIp, updateFileName, resource.exists(), resource.isReadable()));
                return ResponseEntity.notFound().build();
            }
        } catch (MalformedURLException ex) {
            logger.error(String.format("[IP: %s] 文件URL格式错误: %s", clientIp, ex.getMessage()), ex);
            return ResponseEntity.internalServerError().build();
        } catch (Exception ex) {
            logger.error(String.format("[IP: %s] 下载更新文件时发生错误: %s", clientIp, ex.getMessage()), ex);
            return ResponseEntity.internalServerError().build();
        }
    }
    
    /**
     * 获取客户端真实IP地址
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 如果是多级代理，取第一个IP
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }
    
    /**
     * 解密客户端版本号
     * 使用AES-256-CBC模式解密
     */
    private String decryptVersion(String encryptedVersion) throws Exception {
        // 密钥（与客户端保持一致）
        String key = "20250918";
        
        // 确保密钥为32字节（AES-256需要32字节密钥）
        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
        byte[] paddedKey = new byte[32];
        System.arraycopy(keyBytes, 0, paddedKey, 0, Math.min(keyBytes.length, paddedKey.length));
        
        // 解码Base64字符串
        byte[] encryptedData = Base64.getDecoder().decode(encryptedVersion);
        
        // 提取IV（前16字节）
        byte[] iv = new byte[16];
        System.arraycopy(encryptedData, 0, iv, 0, iv.length);
        
        // 提取密文
        byte[] ciphertext = new byte[encryptedData.length - 16];
        System.arraycopy(encryptedData, 16, ciphertext, 0, ciphertext.length);
        
        // 创建解密器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(paddedKey, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        
        // 解密
        byte[] decryptedBytes = cipher.doFinal(ciphertext);
        
        // 转换为字符串
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
}